﻿using System;
using System.Diagnostics;
using System.Linq;

namespace CommonUtils
{
    /// <summary>
    /// 日志工具
    /// sub代表分支
    /// </summary>
    public class LogUtil
    {
        /// <summary>
        /// log开关，只对写入生效，打印照常
        /// 关打印要去ConsoleUtil
        /// </summary>
        public static bool Close = false;

        #region 消息
        //记录格式化次数
        private static ulong _count = 0;

        /// <summary>
        /// 格式化消息 加入时间和换行
        /// </summary>
        public static string Format(object value, params object[] args)
        {
            var msg = value == null ? "null" : value.ToString();
            msg = StringUtil.Format(msg, args);
            msg = string.Format("({0}){1}\r\n{2}{3}\r\n\r\n",
                ++_count, DateTime.Now.ToString("[yyyy/MM/dd HH:mm:ss.fff]"), msg, StringIdentifier.EndField);
            return msg;
        }

        public static string PrintInfo(object value, params object[] args)
        {
            var msg = Format(value, args);
            ConsoleUtil.Write(msg);
            return msg;
        }

        public static string Info(object value, params object[] args)
        => PrintInfo(value, args);

        public static string log(object value, params object[] args)
        => PrintInfo(value, args);

        public static string Print(object value, params object[] args)
        => PrintInfo(value, args);

        public static string Warn(object value, params object[] args)
        {
            var msg = Format(value, args);
            ConsoleUtil.Warn(msg);
            return msg;
        }

        public static string Error(object value, params object[] args)
        {
            var msg = Format(value, args);
            ConsoleUtil.Error(msg);
            return msg;
        }

        public static string InfoJson(object value)
        => PrintInfo(value.GetJson());

        public static string WarnJson(object value)
        => Warn(value.GetJson());

        public static string ErrorJson(object value)
        => Error(value.GetJson());
        #endregion

        #region 路径
        /// <summary>
        /// log路径
        /// </summary>
        private static string GetLogPath(string sub = PathConfig.NoSubIdentifier)
        {
            string date = DateTime.Now.ToString("yyyyMMdd");
            if (string.IsNullOrWhiteSpace(sub) || sub == PathConfig.NoSubIdentifier)
                return PathConfig.LogFolder.Combine(string.Format("log-{0}.log", date));
            else
                return PathConfig.SubLogFolder.Combine(string.Format("{0}/log-{1}.log", sub, date));
        }

        /// <summary>
        /// error路径
        /// </summary>
        private static string GetErrorPath(string sub = PathConfig.NoSubIdentifier)
        {
            string date = DateTime.Now.ToString("yyyyMMdd");
            if (string.IsNullOrWhiteSpace(sub) || sub == PathConfig.NoSubIdentifier)
                return PathConfig.ErrorFolder.Combine(string.Format("error-{0}.log", date));
            else
                return PathConfig.SubErrorFolder.Combine(string.Format("{0}/error-{1}.log", sub, date));
        }
        #endregion

        #region info
        public static void SubRecord(string sub, object value, params object[] args)
        {
            var msg = PrintInfo(value, args);
            if (Close) return;
            FileUtil.AppendWithQueue(GetLogPath(sub), msg);
        }

        public static void Write(object value, params object[] args)
        => SubRecord(PathConfig.NoSubIdentifier, value, args);

        public static void Record(object value, params object[] args)
        => Write(value, args);

        public static void WriteJson(object value)
        => Write(PathConfig.NoSubIdentifier, value.GetJson());

        /// <summary>
        /// 打log,记录堆栈
        /// </summary>
        public static void WriteWithStackTrace(StackTrace stackTrace, string msg, params object[] args)
        => Write(msg + "\r\n" + stackTrace, args);

        /// <summary>
        /// 打log
        /// </summary>
        public static void WriteWithStackTrace(string msg, params object[] args)
        => WriteWithStackTrace(new StackTrace(true), msg, args);
        #endregion

        #region error
        /// <summary>
        /// 异常信息缓存
        /// </summary>
        private static StringStringMap _keyErrorMap = new StringStringMap();

        /// <summary>
        /// 记录异常
        /// </summary>
        public static void SubRecord(string sub, Exception ex)
        {
            //打印错误

            var msg = ex.HelpLink;

            if (!msg.IsNullOrEmpty())
                msg += "\r\n";

            msg += ex.GetType().FullName + ": " + ex.Message;

            if (ex.StackTrace != null)
                msg += "\r\n" + ex.StackTrace.GetLines().Take(5).JoinToText();

            Error(msg);

            //记录错误

            if (Close) return;
            string path = GetErrorPath(sub);

            //考虑到sub为空的情况，加个前缀
            string key = "error-" + sub;
            string value = ex.HelpLink + ex.Message;
            //不重复记录 节省资源
            if (value == _keyErrorMap.Get(key, null, false))
            {
                FileUtil.AppendWithQueue(path, "same as last.");
                return;
            }

            _keyErrorMap.Set(key, ex.Message);

            if (!ex.HelpLink.IsNullOrEmpty())
                FileUtil.AppendWithQueue(path, Format(ex.HelpLink + "\r\n" + ex));
            else
                FileUtil.AppendWithQueue(path, Format(ex));
        }

        public static void Record(Exception ex)
        => SubRecord(PathConfig.NoSubIdentifier, ex);

        /// <summary>
        /// 记录异常
        /// </summary>
        public static void Record(string msg, Exception ex)
        {
            ex.HelpLink += "[" + msg + "]";
            Record(ex);
        }
        #endregion

        /// <summary>
        /// 获取日志内容
        /// </summary>
        public static string GetInfos(string sub = PathConfig.NoSubIdentifier)
        => FileUtil.Read(GetLogPath(sub));

        /// <summary>
        /// 获取异常内容
        /// </summary>
        public static string GetErrors(string sub = PathConfig.NoSubIdentifier)
        => FileUtil.Read(GetErrorPath(sub));

        /// <summary>
        /// 清理日志和异常
        /// </summary> 
        public static void Clear(string sub = PathConfig.NoSubIdentifier)
        {
            FileUtil.Delete(GetLogPath(sub));
            FileUtil.Delete(GetErrorPath(sub));
        }

        public static void Hello()
        {
            "Hello".Print();
        }

        public static void Test()
        => Info("我是打印的log，如果你能看到我证明log工具正常。");
    }
}
